package controllers.displayEntites;

import java.util.Random;

import org.junit.Test;

import core.encryptionDecrypt.EncryptionDecrypt;

/**
 * 加密id 显示实体的基类
 * 
 * @author wsf
 * 
 */
public class SuperDisplay implements EncryptionDecrypt {
	private int a;
	private int b;
	private Long cha;
	// 需要加密的属性
	private Long id;
	// 加密后的值;
	private Long encryptionId;

	// 数据库的ID均为正整数就不用考虑小数点问题了
	// 简单加密 解密 随机数random为一元一次函数系数 开根号 一元一次函数
	// 开根号 根据a奇偶确定开根后正负

	public Long[] encryption(int a, int b, Long id) throws Exception {
		if (a == 0)
			throw new Exception("线性方程a 不能为0");
		if (id == null)
			throw new Exception("id为null");
		Long[] result = new Long[2];

		if (id.toString().contains("."))
			throw new Exception("数据库主键id为小数,id:" + id);
		if (id < 0)
			throw new Exception(" 数据库主键id<0,id:" + id);
		long needEncryptionNumber = id;
		Long cha = 0l;
		// 确保能被开方
		// 由根号x的值和x/2比较大小知道当x>=4以后根号x的值小于x/2
		// 小于4直接为4好了
		if (needEncryptionNumber < 4) {
			cha = 4 - needEncryptionNumber;
			needEncryptionNumber = 4;
		} else {
			// 不小于4的检测到能被开方为正数的数为止
			long idHref = needEncryptionNumber / 2;
			if (needEncryptionNumber % 2 != 0)
				idHref++;
			while (true) {
				if (needEncryptionNumber > Long.MAX_VALUE)
					throw new Exception("已经到达Long类型的最大值了！");
				boolean checkIsCanEncryption = false;
				for (int i = 2; i <= idHref; i++) {
					if (i * i == needEncryptionNumber) {
						checkIsCanEncryption = true;
						break;
					}
				}
				if (!checkIsCanEncryption) {
					needEncryptionNumber++;
					cha++;
					idHref = needEncryptionNumber / 2;
					if (needEncryptionNumber % 2 != 0)
						idHref++;
				} else {
					break;
				}

			}
		}
		// 去小数点转为long
		Long sqrt = new Long(String.valueOf(Math.sqrt(needEncryptionNumber))
				.split("\\.")[0]);

		// System.out.println("sqrt:" + sqrt);
		if (a % 2 != 0)
			sqrt = sqrt - 2 * sqrt;
		result[1] = linearEquationOneUnknown(a, b, sqrt);
		result[0] = cha;
		this.encryptionId = result[1];
		this.cha = cha;
		return result;
	}

	// 解密
	public Long Decrypt(Long needDecryptNumber, Long cha) {
		Long _sqrt = linearEquationOneUnknownDecrypt(this.a, this.b,
				needDecryptNumber);
		return _sqrt * _sqrt - cha;
	}

	public Long DecryptByDisplay() {
		Long _sqrt = linearEquationOneUnknownDecrypt(this.a, this.b,
				this.encryptionId);
		return _sqrt * _sqrt - this.cha;
	}

	// 随机生成参数a,b
	public int[] randomAB() {
		int[] res = new int[2];
		Random r = new Random();
		while (true) {
			res[0] = r.nextInt(18000) - 9000;
			if (res[0] != 0)
				break;

		}
		res[1] = r.nextInt(2000) - 1000;
		return res;
	}

	@Test
	public void test() throws Exception {
		this.setId(61l);
		int[] randomAB = this.randomAB();
		System.out.println("jiami:"
				+ this.setABAndGetId(randomAB[0], randomAB[1]));
		System.out.println("jiemiid:" + this.DecryptByDisplay());
		// System.out.println("id:"+this.getId());

		randomAB = this.randomAB();
		System.out.println("jiami2:"
				+ this.setABAndGetId(randomAB[0], randomAB[1]));
		System.out.println("jiemiid2:" + this.DecryptByDisplay());
		// System.out.println("id:"+this.getId());
	}

	// 加密 綫性方程
	public Long linearEquationOneUnknown(int a, int b, Long sqrt) {
		return a * sqrt + b;

	}

	// 解密 綫性方程
	public Long linearEquationOneUnknownDecrypt(int a, int b,
			Long needDecryptNumber) {
		return (needDecryptNumber - b) / a;

	}

	public static void main(String[] args) throws Exception {
		int a = 1;
		int b = 1;
		SuperDisplay sd = new SuperDisplay();
		sd.setId(6200l);

		System.out.println("res:" + sd.setABAndGetId(a, b));
		System.out.println("jiemi:" + sd.DecryptByDisplay());
		// Long[] res = sd.encryption(a, b);
		// System.out.println("cha:" + res[0] + " encryption:" + res[1]);
		// System.out.println(ae.Number(res));
		// sd.Decrypt(a, b, res[1], res[0]);
		// System.out.println("Decrypt:" + sd.Decrypt(res[1], res[0]));
	}

	public Long setABAndGetId(int a, int b) throws Exception {
		this.a = a;
		this.b = b;
		return Long.valueOf(String.valueOf(encryption(a, b, this.id)[1]));
	}

	// public Long getId() {
	// return id;
	// }

	public void setId(Long id) {
		this.id = id;
	}

	public Long getEncryptionId() {
		return encryptionId;
	}

	public void setEncryptionId(Long encryptionId) {
		this.encryptionId = encryptionId;
	}

}
